package cn.rengy.isql.config;

import cn.hutool.core.util.ReflectUtil;
import cn.rengy.lang.CacheService;
import cn.rengy.util.ExceptionPrintUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.lang.reflect.Method;
import java.time.Duration;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.Callable;
@Slf4j
public class ConcurrentMapCacheService implements CacheService, ApplicationContextAware {
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    private <T> T getBean(String beanName) {
        return (T) applicationContext.getBean(beanName);
    }
    private static final ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();

    public ConcurrentMapCacheService(){
        log.warn("没有注册CacheService,ConcurrentMapCacheService被加载");
    }

    @Override
    public CacheManager getLocalCacheManager() {
        return cacheManager;
    }

    @Override
    public CacheManager getRedisCacheManager() {
        return cacheManager;
    }

    @Override
    public <T> T getLocalCache(String cacheName, String key, Callable<T> valueLoader) {
        Cache cache= cacheManager.getCache(cacheName);
        Cache.ValueWrapper valueWrapper=cache.get(key);
        if (valueWrapper != null) {
            return (T) valueWrapper.get();
        }
        T value;
        try {
            value = valueLoader.call();
            if(value!=null&&value instanceof Collection) {
                if(((Collection)value).isEmpty()) {
                    value=null;
                }
            }
        }catch (Exception ex) {
            log.error(ExceptionPrintUtils.getTrace(ex));
            throw new Cache.ValueRetrievalException(key, valueLoader, ex);
        }
        if(value!=null) {
            cache.put(key, value);
        }
        return value;
    }

    @Override
    public <T> T getLocalCacheIncludeNull(String cacheName, String key, Callable<T> valueLoader) {
        Cache cache= cacheManager.getCache(cacheName);
        Cache.ValueWrapper valueWrapper=cache.get(key.toString());
        if (valueWrapper != null) {
            return (T) valueWrapper.get();
        }
        T value;
        try {
            value = valueLoader.call();
            if(value!=null&&value instanceof Collection) {
                if(((Collection)value).isEmpty()) {
                    value=null;
                }
            }
        }catch (Exception ex) {
            log.error(ExceptionPrintUtils.getTrace(ex));
            throw new Cache.ValueRetrievalException(key, valueLoader, ex);
        }
        cache.put(key, value);
        return value;
    }

    @Override
    public <T> T getCache(String cacheName, String key, Callable<T> valueLoader) {
        return this.getLocalCache(cacheName,key,valueLoader);
    }

    @Override
    public <T> T getCacheIncludeNull(String cacheName, String key, Callable<T> valueLoader) {
        return this.getLocalCache(cacheName,key.toString(),valueLoader);
    }

    @Override
    public <V> void set(String key, V value, Duration timeout) {

    }
}
